TypeScriptã®Exactåãæãäžãã峿 Œãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã§äºæãã¬ããããã£ãé²ããã³ãŒãã®å ç¢æ§ã確ä¿ããŸããå®è·µçãªå¿çšäŸãšãã¹ããã©ã¯ãã£ã¹ãåŠã³ãŸãããã
TypeScriptã®Exactå: å ç¢ãªã³ãŒããå®çŸããå³å¯ãªãªããžã§ã¯ã圢ç¶ãããã³ã°
JavaScriptã®ã¹ãŒããŒã»ããã§ããTypeScriptã¯ãWebéçºã®åçãªäžçã«éçåä»ãããããããŸãã TypeScriptã¯åå®å šæ§ãšã³ãŒãã®ä¿å®æ§ã«ãããŠå€§ããªå©ç¹ãæäŸããŸããããã®æ§é çåä»ãã·ã¹ãã ã¯æãšããŠäºæãã¬åäœã«ã€ãªããããšããããŸããããã§ãExactåïŒå³å¯ãªåïŒãã®æŠå¿µãç»å ŽããŸãã TypeScriptã«ã¯ãExactåããšæç€ºçã«åä»ããããçµã¿èŸŒã¿æ©èœã¯ãããŸããããTypeScriptã®æ©èœãšãã¯ããã¯ãçµã¿åãããããšã§åæ§ã®åäœãå®çŸã§ããŸãããã®ããã°èšäºã§ã¯ãTypeScriptã§ããå³å¯ãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã匷å¶ããã³ãŒãã®å ç¢æ§ãåäžãããäžè¬çãªãšã©ãŒãé²ãæ¹æ³ã«ã€ããŠè©³ãã解説ããŸãã
TypeScriptã®æ§é çåä»ããçè§£ãã
TypeScriptã¯æ§é çåä»ãïŒããã¯ã¿ã€ãã³ã°ãšãåŒã°ããŸãïŒãæ¡çšããŠããŸããããã¯ãåã®äºææ§ã宣èšãããååã§ã¯ãªããåã®ã¡ã³ããŒã«ãã£ãŠæ±ºå®ãããããšãæå³ããŸãã ãªããžã§ã¯ããããåã§èŠæ±ããããã¹ãŠã®ããããã£ãæã£ãŠããã°ã远å ã®ããããã£ãæã£ãŠããŠãããã®åãšäºææ§ããããšèŠãªãããŸãã
äŸãã°ã次ã®ããã«ãªããŸãïŒ
interface Point {
x: number;
y: number;
}
const myPoint = { x: 10, y: 20, z: 30 };
function printPoint(point: Point) {
console.log(`X: ${point.x}, Y: ${point.y}`);
}
printPoint(myPoint); // myPointã« 'z' ããããã£ããã£ãŠããããã¯åé¡ãªãåäœããŸã
ãã®ã·ããªãªã§ã¯ãTypeScriptã¯`myPoint`ãå¿ èŠãª`x`ãš`y`ããããã£ãå«ãã§ãããããäœåãª`z`ããããã£ãæã£ãŠããŠã`printPoint`ã«æž¡ãããšãèš±å¯ããŸãã ãã®æè»æ§ã¯äŸ¿å©ã§ããäžæ¹ãæå³ããäºæãã¬ããããã£ãæã€ãªããžã§ã¯ããæž¡ããŠããŸã£ãå Žåã«ã埮现ãªãã°ã®åå ãšãªãå¯èœæ§ããããŸãã
éå°ãªããããã£ã®åé¡ç¹
æ§é çåä»ãã®å¯å®¹ãã¯ãæã«ãšã©ãŒãé èœããŠããŸãããšããããŸããèšå®ãªããžã§ã¯ããæåŸ ãã颿°ãèããŠã¿ãŸãããïŒ
interface Config {
apiUrl: string;
timeout: number;
}
function setup(config: Config) {
console.log(`API URL: ${config.apiUrl}`);
console.log(`Timeout: ${config.timeout}`);
}
const myConfig = { apiUrl: "https://api.example.com", timeout: 5000, typo: true };
setup(myConfig); // TypeScriptã¯ããã§æå¥ãèšããŸããïŒ
console.log(myConfig.typo); // trueãåºåããŸããäœåãªããããã£ãéãã«ååšããŠããŸã
ãã®äŸã§ã¯ã`myConfig`ã«äœåãªããããã£`typo`ããããŸãã `myConfig`ã¯`Config`ã€ã³ã¿ãŒãã§ãŒã¹ãæºãããŠãããããTypeScriptã¯ãšã©ãŒãçºçãããŸããããããããã®ã¿ã€ãã¯æ±ºããŠææããããããã¿ã€ãã`typoo`ã§ããã¹ãã ã£ãå Žåãã¢ããªã±ãŒã·ã§ã³ã¯æåŸ éãã«åäœããªããããããŸããããããã®äžèŠäºçްãªåé¡ã¯ãè€éãªã¢ããªã±ãŒã·ã§ã³ããããã°ããéã«å€§ããªé çã®çš®ãšãªãåŸãŸãããã¹ãããããªããžã§ã¯ããæ±ãå Žåãããããã£ã®æ¬ èœãã¹ãã«ãã¹ã¯ç¹ã«æ€åºãã«ãããªããŸãã
TypeScriptã§Exactåã匷å¶ããã¢ãããŒã
TypeScriptã§çã®ãExactåãã¯çŽæ¥å©çšã§ããŸããããåæ§ã®çµæãéæãããã峿 Œãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã匷å¶ããããã®ããã€ãã®ãã¯ããã¯ããããŸãïŒ
1. Omitãšåã¢ãµãŒã·ã§ã³ã䜿çšãã
`Omit`ãŠãŒãã£ãªãã£åã䜿çšãããšãæ¢åã®åããç¹å®ã®ããããã£ãé€å€ããŠæ°ããåãäœæã§ããŸãããããåã¢ãµãŒã·ã§ã³ãšçµã¿åãããããšã§ãéå°ãªããããã£ãé²ãã®ã«åœ¹ç«ã¡ãŸãã
interface Point {
x: number;
y: number;
}
const myPoint = { x: 10, y: 20, z: 30 };
// Pointã®ããããã£ã®ã¿ãå«ãåãäœæ
const exactPoint: Point = myPoint as Omit & Point;
// ãšã©ãŒ: å '{ x: number; y: number; z: number; }' ãå 'Point' ã«å²ãåœãŠãããšã¯ã§ããŸããã
// ãªããžã§ã¯ããªãã©ã«ã¯æ¢ç¥ã®ããããã£ã®ã¿æå®ã§ããŸãã'z' ã¯å 'Point' ã«ååšããŸããã
function printPoint(point: Point) {
console.log(`X: ${point.x}, Y: ${point.y}`);
}
//ä¿®æ£
const myPointCorrect = { x: 10, y: 20 };
const exactPointCorrect: Point = myPointCorrect as Omit & Point;
printPoint(exactPointCorrect);
ãã®ã¢ãããŒãã¯ã`myPoint`ã`Point`ã€ã³ã¿ãŒãã§ãŒã¹ã§å®çŸ©ãããŠããªãããããã£ãæã£ãŠããå Žåã«ãšã©ãŒãã¹ããŒããŸãã
è§£èª¬ïŒ `Omit
2. ãªããžã§ã¯ããäœæããããã®é¢æ°ã䜿çšãã
ã€ã³ã¿ãŒãã§ãŒã¹ã§å®çŸ©ãããããããã£ã®ã¿ãåãå ¥ãããã¡ã¯ããªé¢æ°ãäœæã§ããŸãããã®ã¢ãããŒãã¯ããªããžã§ã¯ãäœææç¹ã§ã®åŒ·åãªåãã§ãã¯ãæäŸããŸãã
interface Config {
apiUrl: string;
timeout: number;
}
function createConfig(config: Config): Config {
return {
apiUrl: config.apiUrl,
timeout: config.timeout,
};
}
const myConfig = createConfig({ apiUrl: "https://api.example.com", timeout: 5000 });
//ããã¯ã³ã³ãã€ã«ãããŸããïŒ
//const myConfigError = createConfig({ apiUrl: "https://api.example.com", timeout: 5000, typo: true });
//å '{ apiUrl: string; timeout: number; typo: true; }' ã®åŒæ°ãå 'Config' ã®ãã©ã¡ãŒã¿ãŒã«å²ãåœãŠãããšã¯ã§ããŸããã
// ãªããžã§ã¯ããªãã©ã«ã¯æ¢ç¥ã®ããããã£ã®ã¿æå®ã§ããŸãã'typo' ã¯å 'Config' ã«ååšããŸããã
`Config`ã€ã³ã¿ãŒãã§ãŒã¹ã§å®çŸ©ãããããããã£ã®ã¿ã§æ§æããããªããžã§ã¯ããè¿ãããšã«ãããäœåãªããããã£ãçŽã蟌ãã®ãé²ããŸããããã«ãããããå®å šã«èšå®ãªããžã§ã¯ããäœæã§ããŸãã
3. åã¬ãŒãã䜿çšãã
åã¬ãŒãã¯ãç¹å®ã®ã¹ã³ãŒãå ã§å€æ°ã®åãçµã蟌ã颿°ã§ãããããã¯çŽæ¥çã«éå°ãªããããã£ãé²ãããã§ã¯ãããŸããããæç€ºçã«ãã§ãã¯ããŠé©åãªã¢ã¯ã·ã§ã³ãåãã®ã«åœ¹ç«ã¡ãŸãã
interface User {
id: number;
name: string;
}
function isUser(obj: any): obj is User {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj && typeof obj.id === 'number' &&
'name' in obj && typeof obj.name === 'string' &&
Object.keys(obj).length === 2 //ããŒã®æ°ããã§ãã¯ããŸããæ³šæïŒãã®æ¹æ³ã¯è匱ã§ãUserã®æ£ç¢ºãªããŒæ°ã«äŸåããŸãã
);
}
const potentialUser1 = { id: 123, name: "Alice" };
const potentialUser2 = { id: 456, name: "Bob", extra: true };
if (isUser(potentialUser1)) {
console.log("Valid User:", potentialUser1.name);
} else {
console.log("Invalid User");
}
if (isUser(potentialUser2)) {
console.log("Valid User:", potentialUser2.name); //ããã«ã¯å°éããŸãã
} else {
console.log("Invalid User");
}
ãã®äŸã§ã¯ã`isUser`åã¬ãŒãã¯å¿ é ããããã£ã®ååšã ãã§ãªãããã®åãšããããã£ã®*æ£ç¢ºãª*æ°ããã§ãã¯ããŸãããã®ã¢ãããŒãã¯ããæç€ºçã§ãç¡å¹ãªãªããžã§ã¯ããé©åã«åŠçã§ããŸããããããããããã£æ°ã®ãã§ãã¯ã¯è匱ã§ãã`User`ã«ããããã£ã远å /åé€ããããã³ã«ããã®ãã§ãã¯ãæŽæ°ããå¿ èŠããããŸãã
4. `Readonly`ãš`as const`ã®æŽ»çš
`Readonly`ã¯æ¢åããããã£ã®å€æŽãé²ãã`as const`ã¯ãã¹ãŠã®ããããã£ãæ·±ãèªã¿åãå°çšã§ãªãã©ã«åãæã€èªã¿åãå°çšã®ã¿ãã«ããªããžã§ã¯ããäœæããŸãããããããä»ã®ã¡ãœãããšçµã¿åãããããšã§ããã峿 Œãªå®çŸ©ãšåãã§ãã¯ãäœæããããã«äœ¿çšã§ããŸãããã ããã©ã¡ããåç¬ã§ã¯éå°ãªããããã£ãé²ãããšã¯ã§ããŸããã
interface Options {
width: number;
height: number;
}
//Readonlyåãäœæ
type ReadonlyOptions = Readonly;
const options: ReadonlyOptions = { width: 100, height: 200 };
//options.width = 300; //ãšã©ãŒ: 'width' ã¯èªã¿åãå°çšããããã£ã§ããããã代å
¥ã§ããŸããã
//as constã䜿çš
const config = { api_url: "https://example.com", timeout: 3000 } as const;
//config.timeout = 5000; //ãšã©ãŒ: 'timeout' ã¯èªã¿åãå°çšããããã£ã§ããããã代å
¥ã§ããŸããã
//ããããéå°ãªããããã£ã¯äŸç¶ãšããŠèš±å¯ãããŸãïŒ
const invalidOptions: ReadonlyOptions = { width: 100, height: 200, depth: 300 }; //ãšã©ãŒãªããäŸç¶ãšããŠéå°ãªããããã£ãèš±å¯ããŸãã
interface StrictOptions {
readonly width: number;
readonly height: number;
}
//ããã¯ãšã©ãŒã«ãªããŸãïŒ
//const invalidStrictOptions: StrictOptions = { width: 100, height: 200, depth: 300 };
//å '{ width: number; height: number; depth: number; }' ãå 'StrictOptions' ã«å²ãåœãŠãããšã¯ã§ããŸããã
// ãªããžã§ã¯ããªãã©ã«ã¯æ¢ç¥ã®ããããã£ã®ã¿æå®ã§ããŸãã'depth' ã¯å 'StrictOptions' ã«ååšããŸããã
ããã«ããäžå€æ§ã¯åäžããŸãããé²ããã®ã¯å€æŽã®ã¿ã§ãäœåãªããããã£ã®ååšã¯é²ããŸããã`Omit`ã颿°ã¢ãããŒããšçµã¿åãããããšã§ããã广çã«ãªããŸãã
5. ã©ã€ãã©ãªã®äœ¿çšïŒäŸïŒZod, io-tsïŒ
Zodãio-tsã®ãããªã©ã€ãã©ãªã¯ã匷åãªã©ã³ã¿ã€ã åæ€èšŒãšã¹ããŒãå®çŸ©æ©èœãæäŸããŸãããããã®ã©ã€ãã©ãªã䜿çšãããšãããŒã¿ã®æåŸ ããã圢ç¶ãæ£ç¢ºã«èšè¿°ããã¹ããŒããå®çŸ©ã§ããéå°ãªããããã£ã®é²æ¢ãå«ãŸããŸããã©ã³ã¿ã€ã ã®äŸåé¢ä¿ã远å ãããŸãããéåžžã«å ç¢ã§æè»ãªãœãªã¥ãŒã·ã§ã³ãæäŸããŸãã
Zodã䜿çšããäŸïŒ
import { z } from 'zod';
const UserSchema = z.object({
id: z.number(),
name: z.string(),
});
type User = z.infer;
const validUser = { id: 1, name: "John" };
const invalidUser = { id: 2, name: "Jane", extra: true };
const parsedValidUser = UserSchema.parse(validUser);
console.log("Parsed Valid User:", parsedValidUser);
try {
const parsedInvalidUser = UserSchema.parse(invalidUser);
console.log("Parsed Invalid User:", parsedInvalidUser); // ããã«ã¯å°éããŸãã
} catch (error) {
console.error("Validation Error:", error.errors);
}
Zodã®`parse`ã¡ãœããã¯ãå ¥åãã¹ããŒãã«æºæ ããŠããªãå Žåã«ãšã©ãŒãã¹ããŒãã广çã«éå°ãªããããã£ãé²ããŸããããã«ããã©ã³ã¿ã€ã æ€èšŒãæäŸãããã¹ããŒãããTypeScriptã®åãçæããããããåå®çŸ©ãšã©ã³ã¿ã€ã æ€èšŒããžãã¯éã®äžè²«æ§ãä¿èšŒãããŸãã
Exactåã匷å¶ããããã®ãã¹ããã©ã¯ãã£ã¹
TypeScriptã§ãã峿 Œãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã匷å¶ããéã«èæ ®ãã¹ããã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãïŒ
- é©åãªãã¯ããã¯ãéžæããïŒ æé©ãªã¢ãããŒãã¯ãç¹å®ã®ããŒãºããããžã§ã¯ãã®èŠä»¶ã«äŸåããŸããåçŽãªã±ãŒã¹ã§ã¯ã`Omit`ãšã®åã¢ãµãŒã·ã§ã³ããã¡ã¯ããªé¢æ°ã§ååãããããŸãããããè€éãªã·ããªãªãã©ã³ã¿ã€ã æ€èšŒãå¿ èŠãªå Žåã¯ãZodãio-tsã®ãããªã©ã€ãã©ãªã®äœ¿çšãæ€èšããŠãã ããã
- äžè²«æ§ãä¿ã€ïŒ éžæããã¢ãããŒããã³ãŒãããŒã¹å šäœã§äžè²«ããŠé©çšããåäžãªã¬ãã«ã®åå®å šæ§ãç¶æããŸãã
- åãææžåããïŒ ã€ã³ã¿ãŒãã§ãŒã¹ãšåãæç¢ºã«ææžåããããŒã¿ã®æåŸ ããã圢ç¶ãä»ã®éçºè ã«äŒããŸãã
- ã³ãŒãããã¹ãããïŒ ãŠããããã¹ããäœæããŠãåã®å¶çŽãæåŸ ã©ããã«æ©èœããŠããããšãããã³ã³ãŒããç¡å¹ãªããŒã¿ãé©åã«åŠçããããšã確èªããŸãã
- ãã¬ãŒããªããèæ ®ããïŒ ãã峿 Œãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã匷å¶ãããšã³ãŒãã¯å ç¢ã«ãªããŸãããéçºæéãå¢å ããå¯èœæ§ããããŸããå©ç¹ãšã³ã¹ããæ¯èŒæ€èšãããããžã§ã¯ãã«æãé©ããã¢ãããŒããéžæããŠãã ããã
- 段éçã«æ¡çšããïŒ å€§èŠæš¡ãªæ¢åã®ã³ãŒãããŒã¹ã§äœæ¥ããŠããå Žåã¯ãã¢ããªã±ãŒã·ã§ã³ã®æãéèŠãªéšåããå§ããŠããããã®ãã¯ããã¯ã段éçã«æ¡çšããããšãæ€èšããŠãã ããã
- ãªããžã§ã¯ã圢ç¶ãå®çŸ©ããéã¯ãåãšã€ãªã¢ã¹ãããã€ã³ã¿ãŒãã§ãŒã¹ãåªå ããïŒ ã€ã³ã¿ãŒãã§ãŒã¹ã¯å®£èšã®ããŒãžããµããŒãããŠãããããäžè¬çã«æšå¥šãããŸããããã¯ãç°ãªããã¡ã€ã«éã§åãæ¡åŒµããã®ã«åœ¹ç«ã¡ãŸãã
å®äžçã®äŸ
Exactåãæçãšãªãå®äžçã®ã·ããªãªãããã€ãèŠãŠã¿ãŸãããïŒ
- APIãªã¯ãšã¹ããã€ããŒãïŒ APIã«ããŒã¿ãéä¿¡ããéããã€ããŒããæåŸ ãããã¹ããŒãã«æºæ ããŠããããšã確èªããããšãéèŠã§ããExactåã匷å¶ããããšã§ãäºæããªãããããã£ã®éä¿¡ã«ãããšã©ãŒãé²ãããšãã§ããŸããäŸãã°ãå€ãã®æ±ºæžåŠçAPIã¯äºæãã¬ããŒã¿ã«å¯ŸããŠéåžžã«ææã§ãã
- èšå®ãã¡ã€ã«ïŒ èšå®ãã¡ã€ã«ã«ã¯å€æ°ã®ããããã£ãå«ãŸããããšãå€ããã¿ã€ããäžè¬çã§ããExactåã䜿çšãããšããããã®ã¿ã€ããæ©æã«çºèŠã§ããŸããã¯ã©ãŠãå±éã§ãµãŒããŒã®å Žæãèšå®ããå Žåãå Žæã®èšå®ïŒäŸïŒeu-west-1 vs. eu-wet-1ïŒã®ã¿ã€ãã¯ãäºåã«ææãããªããšãããã°ãéåžžã«å°é£ã«ãªããŸãã
- ããŒã¿å€æãã€ãã©ã€ã³ïŒ ãããã©ãŒãããããå¥ã®ãã©ãŒããããžããŒã¿ã倿ããéãåºåããŒã¿ãæåŸ ãããã¹ããŒãã«æºæ ããŠããããšã確èªããããšãéèŠã§ãã
- ã¡ãã»ãŒãžãã¥ãŒïŒ ã¡ãã»ãŒãžãã¥ãŒãä»ããŠã¡ãã»ãŒãžãéä¿¡ããéãã¡ãã»ãŒãžãã€ããŒããæå¹ã§æ£ããããããã£ãå«ãã§ããããšã確èªããããšãéèŠã§ãã
äŸïŒåœéåïŒi18nïŒèšå®
å€èšèªã¢ããªã±ãŒã·ã§ã³ã®ç¿»èš³ã管çããããšãæ³åããŠã¿ãŠãã ãããæ¬¡ã®ãããªèšå®ãªããžã§ã¯ãããããããããŸããïŒ
interface Translation {
greeting: string;
farewell: string;
}
interface I18nConfig {
locale: string;
translations: Translation;
}
const englishConfig: I18nConfig = {
locale: "en-US",
translations: {
greeting: "Hello",
farewell: "Goodbye"
}
};
//éå°ãªããããã£ãååšããéãã«ãã°ãå°å
¥ãããããããã¯åé¡ã«ãªããŸãã
const spanishConfig: I18nConfig = {
locale: "es-ES",
translations: {
greeting: "Hola",
farewell: "Adiós",
typo: "unintentional translation"
}
};
//解決çïŒOmitã䜿çšãã
const spanishConfigCorrect: I18nConfig = {
locale: "es-ES",
translations: {
greeting: "Hola",
farewell: "Adiós"
} as Omit & Translation
};
Exactåããªããšã翻蚳ããŒã®ã¿ã€ãïŒ`typo`ãã£ãŒã«ãã远å ãããªã©ïŒãèŠéãããããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ã§ç¿»èš³ãæ¬ èœããåå ãšãªãå¯èœæ§ããããŸãããã峿 Œãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã匷å¶ããããšã§ããããã®ãšã©ãŒãéçºäžã«ææããæ¬çªç°å¢ã«å°éããã®ãé²ãããšãã§ããŸãã
çµè«
TypeScriptã«ã¯çµã¿èŸŒã¿ã®ãExactåãã¯ãããŸãããã`Omit`ãšã®åã¢ãµãŒã·ã§ã³ããã¡ã¯ããªé¢æ°ãåã¬ãŒãã`Readonly`ã`as const`ããããŠZodãio-tsã®ãããªå€éšã©ã€ãã©ãªãšãã£ãTypeScriptã®æ©èœãšãã¯ããã¯ãçµã¿åãããããšã§ãåæ§ã®çµæãéæã§ããŸãããã峿 Œãªãªããžã§ã¯ã圢ç¶ãããã³ã°ã匷å¶ããããšã§ãã³ãŒãã®å ç¢æ§ãåäžãããäžè¬çãªãšã©ãŒãé²ããã¢ããªã±ãŒã·ã§ã³ã®ä¿¡é Œæ§ãé«ããããšãã§ããŸããèªåã®ããŒãºã«æãåã£ãã¢ãããŒããéžæããã³ãŒãããŒã¹å šäœã§äžè²«ããŠé©çšããããšãå¿ããªãã§ãã ããããããã®ã¢ãããŒããæ éã«æ€èšããããšã§ãã¢ããªã±ãŒã·ã§ã³ã®åãããå³å¯ã«å¶åŸ¡ããé·æçãªä¿å®æ§ãåäžãããããšãã§ããŸãã